﻿// This code is released under the BSD license.
namespace PugLib.Math
{
    using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.Diagnostics.CodeAnalysis;
    using System.Threading;
	using System.Threading.Tasks;

    public static class PythagoreanTuples
    {
        [SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes")]
        private static readonly Func<long, long, long, bool>
            IsPythagoreanTuple = (a, b, c) => (c * c) == ((a * a) + (b * b));


        public static IDictionary GetPythagoreanTuplesInRange(int startValue, int endValue)
        {
            return GetPythagoreanTuplesInRangeOuterParallel(startValue, endValue);
        }

        public static IDictionary GetPythagoreanTuplesInRangeSerial(int startValue, int endValue)
        {
            Dictionary<Guid, Tuple<int, int, int>> rtn = new Dictionary<Guid, Tuple<int, int, int>>();
            for (int x = startValue; x <= endValue; x++)
            {
                for (int y = x + 1; y <= endValue; y++)
                {
                    for (int z = y + 1; z <= endValue; z++)
                    {
                        if (IsPythagoreanTuple(x, y, z))
                        {
                            rtn.Add(Guid.NewGuid(), new Tuple<int, int, int>(x, y, z));
                        }
                    }
                }
            }
            Console.WriteLine("Found " + rtn.Count + " tuples");
            return rtn;
        }

        public static IDictionary GetPythagoreanTuplesInRangeOuterParallel(int startValue, int endValue)
        {
            Dictionary<Guid, Tuple<int, int, int>> rtn = new Dictionary<Guid, Tuple<int, int, int>>();
            Parallel.For(startValue, endValue, x =>
                                                   {
                                                       for (int y = x + 1; y <= endValue; y++)
                                                       {
                                                           for (int z = y + 1; z <= endValue; z++)
                                                           {
                                                               if (IsPythagoreanTuple(x, y, z))
                                                               {
                                                                   rtn.Add(Guid.NewGuid(), new Tuple<int, int, int>(x, y, z));
                                                               }
                                                           }
                                                       }
                                                   });
            Console.WriteLine("Found " + rtn.Count + " tuples");
            return rtn;
        }


        public static IDictionary GetPythagoreanTuplesInRangeOuterAndMiddleParallel(int startValue, int endValue)
        {
            Dictionary<Guid, Tuple<int, int, int>> rtn = new Dictionary<Guid, Tuple<int, int, int>>();
            Parallel.For(startValue, endValue,
                         x => Parallel.For(x + 1, endValue, y =>
                                                                {
                                                                    for (int z = y + 1; z <= endValue; z++)
                                                                    {
                                                                        if (IsPythagoreanTuple(x, y, z))
                                                                        {
                                                                            rtn.Add(Guid.NewGuid(), new Tuple<int, int, int>(x, y, z));
                                                                        }
                                                                    }
                                                                }));
            Console.WriteLine("Found " + rtn.Count + " tuples");
            return rtn;
        }
    }
}